local _M = { _VERSION = "0.1" }

local response  = require("shared.api.response")
local httparg   = require("shared.httparg")

local accesstoken = require("shared.auth.accesstoken")
local jwt         = require("shared.auth.jwt")

local def        = require("shared.api.def")
local ERROR_CODE = def.ERROR_CODE

local HTTP_HEADER_X_ACCESS_TOKEN = "X-Access-Token"

local VALIDATORS = {}
do
  function VALIDATORS.accesstoken(v)
    if v == nil then
      return nil
    end

    local ticket, version, err = accesstoken.unpack(v)
    if err then
      return nil, {
        code = ERROR_CODE.INVALID_ACCESS_TOKEN,
      }
    end

    -- set default if nil
    ticket.extraData   = ticket.extraData    or {}
    ticket.permissions = ticket.permissions  or {}

    if accesstoken.is_expired(ticket, ngx.time()) then
      return nil, {
        code = ERROR_CODE.ACCESS_TOKEN_EXPIRED,
      }
    end

    if type(ticket)=="table" then
      ticket._version = version
      return accesstoken.ticket.new(ticket)
    end
    return nil
  end


  function VALIDATORS.jwt(v)
    if v == nil then
      return nil
    end

    local reply, err = jwt.unpack(v)
    if err then
      return nil, {
        code = ERROR_CODE.INVALID_ACCESS_TOKEN,
      }
    end

    if not reply.verified then
      return nil, {
        code = ERROR_CODE.ACCESS_TOKEN_EXPIRED,
      }
    end

    if type(reply)=="table" then
      return jwt.ticket.new(reply)
    end
    return nil
  end

  -- export
  _M.validator = VALIDATORS
end


-- _M
do

  function _M.tag(opt)
    opt = opt or {}
    opt.error_handler = opt.error_handler  or  response.failure

    return httparg.tag(opt)
  end


  --[[
    argument:
      tag              (httparg.tag)
      token_validator  (function)
      ...              (extra handlers)
  ]]
  function _M.accesstoken( tag, token_validator, ...)
    local args = {token_validator, ...}
    return tag.header[HTTP_HEADER_X_ACCESS_TOKEN](unpack(args))
  end


  function _M.response_accesstoken(header, token)
    if type(token)=="string"  and  token ~= "" then
      header[HTTP_HEADER_X_ACCESS_TOKEN] = token
    end
  end
end

_M.assertion = httparg.assertion
return _M
